﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.Threading.Tasks;

namespace MrBrooks.Utility
{
    /// <summary>
    /// 消息显示器
    /// </summary>
    public class MessageShower
    {
        private readonly TextBox txtContent;
        private DateTime lastDisplayTime = DateTime.Now;
        private readonly List<string> contentList;

        /// <summary>
        /// 是否主窗体正在关闭
        /// </summary>
        private bool isClosing = false;

        /// <summary>
        /// 最后一条消息
        /// </summary>
        private string lastMessage = string.Empty;

        /// <summary>
        /// 是否有新内容
        /// </summary>
        private bool modified = false;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="control"></param>
        public MessageShower(TextBox control)
        {
            txtContent = control;
            control.ReadOnly = true;
            control.ScrollBars = ScrollBars.Vertical;

            contentList = new List<string>(LinesMax);
            DefaultTitle = control.FindForm().GetType().Name;

            var findForm = txtContent.FindForm();
            if (findForm != null) findForm.FormClosing += this.ProcessFormClosing;
            var menu = new ContextMenu();
            menu.MenuItems.Add(new MenuItem("Cl&ear", this.Clear));
            menu.MenuItems.Add(new MenuItem("&Copy All", this.Copy));
            txtContent.ContextMenu = menu;

            Task.Factory.StartNew(() =>
            {
                while (!isClosing)
                {
                    Thread.Sleep(100);
                    if (lastDisplayTime.AddMilliseconds(DisplayInterval) < DateTime.Now)
                    {
                        Display();
                    }
                }
            });
        }

        /// <summary>
        /// 清除所有内容
        /// </summary>
        public void Clear()
        {
            Clear(null, null);
        }

        /// <summary>
        /// 清除内容
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Clear(object sender, EventArgs e)
        {
            lock (contentList)
            {
                contentList.Clear();
            }

            txtContent.Text = "";
        }

        /// <summary>
        /// 复制内容到剪贴板
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Copy(object sender, EventArgs e)
        {
            var text = txtContent.Text;
            if (!string.IsNullOrEmpty(text))
            {
                try
                {
                    Clipboard.SetText(text);
                }
                catch (Exception ex)
                {
                    Show("复制出错：" + ex.Message);
                }
            }
        }

        /// <summary>
        /// 是否需要显示
        /// </summary>
        private void Display()
        {
            if (!modified) return;
            if (Pause) return;

            if (lastDisplayTime.AddMilliseconds(DisplayInterval) < DateTime.Now)
            {
                // 设置为未改变
                modified = false;
                lastDisplayTime = DateTime.Now;

                string content;
                lock (contentList)
                {
                    content = string.Join("\r\n", contentList);
                }

                if (!string.IsNullOrEmpty(content))
                {
                    Display(content, null);
                }
            }
        }

        /// <summary>
        /// 显示日志
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        private void Display(object sender, EventArgs args)
        {
            if (txtContent.InvokeRequired)
            {
                txtContent.BeginInvoke(new EventHandler(Display), sender, args);
            }
            else
            {
                string message = (string)sender;
                txtContent.Text = message;
                txtContent.SelectionStart = message.Length;
                txtContent.ScrollToCaret();
            }
        }

        /// <summary>
        /// 处理所在窗体正在关闭的事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ProcessFormClosing(object sender, FormClosingEventArgs e)
        {
            isClosing = true;
        }

        #region .Public Methods.
        /// <summary>
        /// 以默认标题显示日志
        /// </summary>
        /// <param name="message"></param>
        public void Show(string message)
        {
            Show(DefaultTitle, message);
        }

        /// <summary>
        /// 显示日志
        /// </summary>
        /// <param name="title">标题</param>
        /// <param name="message">内容</param>
        public void Show(string title, string message)
        {
            if (txtContent != null)
            {
                if (!DisplaySameContent)
                {
                    if (lastMessage == (title + message))
                    {
                        return;
                    }

                    lastMessage = title + message;
                }

                modified = true;
                string content = string.Format("[{0}] ({1}) {2}", DateTime.Now.ToString("HH:mm:ss"), title, message);
                lock (contentList)
                {
                    contentList.Add(content);
                    int over = contentList.Count - LinesMax;
                    if (over > 0)
                    {
                        for (int i = 0; i < over; i++)
                        {
                            contentList.RemoveAt(0);
                        }
                    }
                }
            }
        }
        #endregion

        #region .Public Properties.
        /// <summary>
        /// 是否允许显示和最后一条一样的消息
        /// </summary>
        public bool DisplaySameContent = true;

        /// <summary>
        /// 标题
        /// </summary>
        public string DefaultTitle = string.Empty;

        /// <summary>
        /// 最大显示行数, 默认100
        /// </summary>
        public int LinesMax = 100;

        /// <summary>
        /// 显示频率, 单位: 毫秒
        /// </summary>
        public int DisplayInterval = 400;

        /// <summary>
        /// 是否暂停显示
        /// </summary>
        public bool Pause { get; set; }
        #endregion
    }
}
